Skip to content

Commit

Permalink
Merging latest release-23.03 into master (#24264)
Browse files Browse the repository at this point in the history
* Update release version for dotcms-ui and dotcms-webcomponents

* Modify dotcmsReleaseVersion to 23.03, coreWebReleaseVersion, webComponentsReleaseVersion to rc and dot-cicd branch version to release-23.03

* Update branch in git submodule to release-23.03

* Excluding from triggering test at folder: dotCMS/src/main/webapp/html

* #23977 Block editor freeze scroll on tippy menus show (#24180)

* dev: freeze scroll on show forms #23977

* clean up

* refactor

* clean up v2

* feedback

* clean up

* #24172 Refresh Page portlet's data when site changed (#24175)

* #24031 fix block editor not saving (#24222)

* Fix #24032 Bring it to 22.03 (#24229)

* Fix #24032 Bring it to 22.03

* Build de lib

---------

Co-authored-by: Manuel Rojas <manuel.rojas.21@gmail.com>

* #24240 Fix data-access tests in 23.03 (#24244)

* #24240 fix test cases

* #24240 fix lint

* fire release docker image generation

* #24221 fix Snapshots should be displayed when the language is changed (#24234)

* Fix #23449 show dotAssets in folder listing

* Fixing merge conflict in

* Merging conflicts

* Merging conflicts

---------

Co-authored-by: victoralfaro-dotcms <victor.alfaro@dotcms.com>
Co-authored-by: Rafael Velazco <rjvelazco21@gmail.com>
Co-authored-by: alfredo-dotcms <37185433+alfredo-dotcms@users.noreply.github.com>
Co-authored-by: Freddy Montes <751424+fmontes@users.noreply.github.com>
Co-authored-by: Manuel Rojas <manuel.rojas.21@gmail.com>
Co-authored-by: zulqarnainvd <113915849+zulqarnainvd@users.noreply.github.com>
Co-authored-by: hassan-mustafa-baig <111717530+hassan-mustafa-baig@users.noreply.github.com>
  • Loading branch information
8 people committed Mar 6, 2023
1 parent 48aaecb commit 164d3e8
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 48 deletions.
Expand Up @@ -35,7 +35,7 @@
<dot-pages-card
*ngFor="let item of vm.favoritePages.items; let i = index"
[actionButtonId]="'favoritePageActionButton-' + i"
[imageUri]="item.screenshot + '?' + timeStamp"
[imageUri]="item.screenshot + '?language_id=' + item.languageId + '&' + timeStamp"
[title]="item.title"
[url]="item.url"
[ownerPage]="item.owner === vm.loggedUser.id"
Expand Down
Expand Up @@ -48,6 +48,7 @@ export const favoritePagesInitialTestData = [
...dotcmsContentletMock,
live: true,
baseType: 'CONTENT',
languageId: '1',
modDate: '2020-09-02 16:45:15.569',
title: 'preview1',
screenshot: 'test1',
Expand All @@ -57,6 +58,7 @@ export const favoritePagesInitialTestData = [
{
...dotcmsContentletMock,
title: 'preview2',
languageId: '1',
modDate: '2020-09-02 16:45:15.569',
screenshot: 'test2',
url: '/index2',
Expand Down Expand Up @@ -230,7 +232,7 @@ describe('DotPagesFavoritePanelComponent', () => {
expect(elem.length).toBe(2);
expect(
elem[0].componentInstance.imageUri.includes(
favoritePagesInitialTestData[0].screenshot
`${favoritePagesInitialTestData[0].screenshot}?language_id=${favoritePagesInitialTestData[0].languageId}`
)
).toBe(true);
expect(elem[0].componentInstance.title).toBe(favoritePagesInitialTestData[0].title);
Expand Down
@@ -1,3 +1,5 @@
import { Subject } from 'rxjs';

import { Component, DebugElement, EventEmitter, Input, Output } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
Expand All @@ -11,6 +13,7 @@ import { DotMessageSeverity, DotMessageType } from '@components/dot-message-disp
import { DotMessageDisplayService } from '@components/dot-message-display/services';
import { DotRouterService } from '@dotcms/app/api/services/dot-router/dot-router.service';
import { DotEventsService } from '@dotcms/data-access';
import { mockSites, SiteService } from '@dotcms/dotcms-js';
import { dotcmsContentletMock, MockDotRouterService } from '@dotcms/utils-testing';

import { DotPageStore } from './dot-pages-store/dot-pages.store';
Expand Down Expand Up @@ -110,6 +113,8 @@ describe('DotPagesComponent', () => {
let dotRouterService: DotRouterService;
let dotMessageDisplayService: DotMessageDisplayService;

const switchSiteSubject = new Subject();

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
Expand All @@ -122,7 +127,19 @@ describe('DotPagesComponent', () => {
providers: [
DotEventsService,
{ provide: DotMessageDisplayService, useClass: DotMessageDisplayServiceMock },
{ provide: DotRouterService, useClass: MockDotRouterService }
{ provide: DotRouterService, useClass: MockDotRouterService },
{
provide: SiteService,
useValue: {
get currentSite() {
return undefined;
},

get switchSite$() {
return switchSiteSubject.asObservable();
}
}
}
]
}).compileComponents();
});
Expand Down Expand Up @@ -240,4 +257,10 @@ describe('DotPagesComponent', () => {
});
expect(store.getPages).toHaveBeenCalledWith({ offset: 0 });
});

it('should reload portlet only when the site change', () => {
switchSiteSubject.next(mockSites[0]); // setting the site
switchSiteSubject.next(mockSites[1]); // switching the site
expect(store.getPages).toHaveBeenCalledWith({ offset: 0 });
});
});
Expand Up @@ -5,12 +5,13 @@ import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/co
import { Menu } from 'primeng/menu';

import { Observable } from 'rxjs/internal/Observable';
import { filter, takeUntil } from 'rxjs/operators';
import { filter, skip, takeUntil } from 'rxjs/operators';

import { DotMessageSeverity, DotMessageType } from '@components/dot-message-display/model';
import { DotMessageDisplayService } from '@components/dot-message-display/services';
import { DotRouterService } from '@dotcms/app/api/services/dot-router/dot-router.service';
import { DotEventsService } from '@dotcms/data-access';
import { SiteService } from '@dotcms/dotcms-js';
import { DotCMSContentlet } from '@dotcms/dotcms-models';

import { DotPagesState, DotPageStore } from './dot-pages-store/dot-pages.store';
Expand Down Expand Up @@ -41,6 +42,7 @@ export class DotPagesComponent implements OnInit, OnDestroy {
private dotRouterService: DotRouterService,
private dotMessageDisplayService: DotMessageDisplayService,
private dotEventsService: DotEventsService,
private dotSiteService: SiteService,
private element: ElementRef
) {
this.store.setInitialStateData(FAVORITE_PAGE_LIMIT);
Expand Down Expand Up @@ -115,6 +117,10 @@ export class DotPagesComponent implements OnInit, OnDestroy {
type: DotMessageType.SIMPLE_MESSAGE
});
});

this.dotSiteService.switchSite$.pipe(takeUntil(this.destroy$), skip(1)).subscribe(() => {
this.store.getPages({ offset: 0 });
});
}

ngOnDestroy(): void {
Expand Down
Expand Up @@ -145,6 +145,14 @@ export const changeToItems: DotMenuItem[] = [
...suggestionOptions.filter((item) => !FORBIDDEN_CHANGE_TO_BLOCKS[item.id])
];

export const clearFilter = function ({ type, editor, range, suggestionKey, ItemsType }) {
const queryRange = {
to: range.to + suggestionKey.getState(editor.view.state).query?.length,
from: type === ItemsType.BLOCK ? range.from : range.from + 1
};
editor.chain().deleteRange(queryRange).run();
};

export const BASIC_TIPPY_OPTIONS: Partial<Props> = {
duration: [250, 0],
interactive: true,
Expand All @@ -161,11 +169,3 @@ export const BASIC_TIPPY_OPTIONS: Partial<Props> = {
]
}
};

export const clearFilter = function ({ type, editor, range, suggestionKey, ItemsType }) {
const queryRange = {
to: range.to + suggestionKey.getState(editor.view.state).query?.length,
from: type === ItemsType.BLOCK ? range.from : range.from + 1
};
editor.chain().deleteRange(queryRange).run();
};
Expand Up @@ -61,7 +61,7 @@ describe('DotESContentService', () => {

const req = httpMock.expectOne('/api/content/_search');
expect(req.request.method).toBe('POST');
expect(req.request.body).toBe(
expect(req.request.body).toEqual(
'{"query":"+contentType: blog +languageId : 2 ","sort":"name ASC","limit":5,"offset":"10"}'
);
req.flush({ entity: responseData });
Expand Down
4 changes: 2 additions & 2 deletions core-web/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Expand Up @@ -4,12 +4,11 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import com.dotcms.datagen.ContentletDataGen;
import com.dotcms.datagen.TemplateDataGen;
import com.dotcms.datagen.VariantDataGen;
import com.dotcms.variant.model.Variant;
import com.dotmarketing.db.DbConnectionFactory;
import com.dotmarketing.exception.DotRuntimeException;
import com.dotmarketing.portlets.contentlet.model.Contentlet.ContentletHashMap;
import java.io.File;
import java.io.IOException;
import java.net.URL;
Expand Down Expand Up @@ -77,6 +76,8 @@ public class BrowserAPITest extends IntegrationTestBase {

static Link testlink;

private static BrowserAPIImpl browserAPIImpl;

@BeforeClass
public static void prepare() throws Exception {
//Setting web app environment
Expand Down Expand Up @@ -120,7 +121,7 @@ public static void prepare() throws Exception {
testPage = APILocator.getHTMLPageAssetAPI().fromContentlet(HTMLPageDataGen.checkin(page, IndexPolicy.FORCE));

testlink = new LinkDataGen().hostId(testHost.getIdentifier()).title("testLink").parent(testFolder).target("https://google.com").linkType("EXTERNAL").nextPersisted();

browserAPIImpl = (BrowserAPIImpl) APILocator.getBrowserAPI();
}

/**
Expand Down Expand Up @@ -578,30 +579,79 @@ public void test_getFolderContent_pageWithTwoVariants()
final Variant secondVariant = new VariantDataGen().nextPersisted();

final HTMLPageAsset pageInDefaultVariant = new HTMLPageDataGen(site, template_A).folder(folder)
.nextPersisted();
.nextPersisted();

final HTMLPageAsset pageInSecondVariant = (HTMLPageAsset) new HTMLPageDataGen(site, template_A)
.folder(folder)
.variant(secondVariant)
.nextPersisted();
.folder(folder)
.variant(secondVariant)
.nextPersisted();

final BrowserQuery browserQuery = BrowserQuery.builder()
.showDotAssets(Boolean.FALSE)
.showLinks(Boolean.TRUE)
.withHostOrFolderId(folder.getIdentifier())
.showFiles(true)
.showPages(true)
.showFolders(false)
.showArchived(false)
.showWorking(Boolean.TRUE)
.sortByDesc(false)
.withUser(user).build();
.showDotAssets(Boolean.FALSE)
.showLinks(Boolean.TRUE)
.withHostOrFolderId(folder.getIdentifier())
.showFiles(true)
.showPages(true)
.showFolders(false)
.showArchived(false)
.showWorking(Boolean.TRUE)
.sortByDesc(false)
.withUser(user).build();

final Map<String, Object> results = browserAPI.getFolderContent(browserQuery);
assertEquals(1, ((int) results.get("total")));
assertEquals(pageInDefaultVariant.getIdentifier(),
((ContentletHashMap)((List) results.get("list")).get(0)).get("identifier"));
((Contentlet.ContentletHashMap)((List) results.get("list")).get(0)).get("identifier"));

}

}

@Test
public void getAssetNameColumn_providedBaseQuery_shouldGenerateCorrectSQLForDB() throws DotDataException, DotSecurityException {

final String sql = browserAPIImpl.getAssetNameColumn("LOWER(%s) LIKE ? ");

assertNotNull(sql);
if (DbConnectionFactory.isPostgres()) {
assertTrue(sql.contains("-> 'fields' -> 'asset' -> 'metadata' ->> 'name'"));
}
else{
assertTrue(sql.contains("$.fields.asset.metadata.name"));
}
}

@Test
public void getFolderContent_searchDotAssetWithFilter_shouldReturnNotNull() throws DotDataException, DotSecurityException {
final String filterText = "company_logo.png";
final User user = APILocator.systemUser();
final List<String> mimeTypes = List.of("image");

final BrowserQuery browserQuery = BrowserQuery.builder()
.withUser(user)
.withHostOrFolderId("SYSTEM_HOST")
.offset(0)
.maxResults(1)
.withFilter(filterText)
.showMimeTypes(mimeTypes)
.showImages(mimeTypes.contains(mimeTypes.get(0)))
.showExtensions(null)
.showWorking(true)
.showArchived(false)
.showFolders(false)
.showFiles(true)
.showShorties(false)
.showContent(true)
.sortBy("modDate")
.sortByDesc(true)
.showLinks(false)
.withLanguageId(1)
.showDotAssets(true)
.build();

final List<Contentlet> contentletList = browserAPI.getContentUnderParentFromDB(browserQuery);
final Map<String, Object> result = browserAPI.getFolderContent(browserQuery);

assertNotNull(contentletList);
assertNotNull(result);
}

}
2 changes: 1 addition & 1 deletion dotCMS/src/main/enterprise
55 changes: 51 additions & 4 deletions dotCMS/src/main/java/com/dotcms/browser/BrowserAPIImpl.java
@@ -1,6 +1,7 @@
package com.dotcms.browser;

import com.dotcms.business.CloseDBIfOpened;
import com.dotcms.content.business.json.ContentletJsonAPI;
import com.dotcms.contenttype.model.type.BaseContentType;
import com.dotcms.uuid.shorty.ShortyIdAPI;
import com.dotmarketing.beans.Host;
Expand Down Expand Up @@ -55,6 +56,17 @@ public class BrowserAPIImpl implements BrowserAPI {
private final PermissionAPI permissionAPI = APILocator.getPermissionAPI();
private final ShortyIdAPI shortyIdAPI = APILocator.getShortyAPI();

private static final StringBuilder POSTGRES_ASSETNAME_COLUMN = new StringBuilder(ContentletJsonAPI
.CONTENTLET_AS_JSON).append("-> 'fields' -> ").append("'asset' -> 'metadata' ->> ").append("'name' ");

private static final StringBuilder MSSQL_ASSETNAME_COLUMN = new StringBuilder("JSON_VALUE(c.").append
(ContentletJsonAPI.CONTENTLET_AS_JSON).append(", '$.fields.").append("asset.metadata.").append("name')" +
" ");

private static final StringBuilder ASSET_NAME_LIKE = new StringBuilder().append("LOWER(%s) LIKE ? ");

private final String OR = " OR ";

/**
* Returns a collection of contentlets based on diff attributes of the BrowserQuery
* e.g folder, host, archived, baseTypes, language.
Expand Down Expand Up @@ -276,13 +288,28 @@ private Tuple2<String, List<Object>> selectQuery(final BrowserQuery browserQuery
sqlQuery.append(" and id.parent_path=? ");
parameters.add(browserQuery.folder.getPath());
}
if (UtilMethods.isSet(browserQuery.luceneQuery)) {
final String filterText = browserQuery.luceneQuery.toLowerCase();
if (UtilMethods.isSet(browserQuery.filter)) {
final String filterText = browserQuery.filter.toLowerCase().trim();
final String[] spliter = filterText.split(" ");
for (final String token : spliter) {
sqlQuery.append(" and LOWER(c.title) like ?");

sqlQuery.append(" and (");
for (int indx = 0; indx < spliter.length; indx++) {
final String token = spliter[indx];
if(token.equals(StringPool.BLANK)){
continue;
}
sqlQuery.append(" LOWER(c.title) like ?");
parameters.add("%" + token + "%");
if(indx + 1 < spliter.length){
sqlQuery.append(" and");
}
}

sqlQuery.append(OR);
sqlQuery.append(getAssetNameColumn(ASSET_NAME_LIKE.toString()));
sqlQuery.append(" ) ");

parameters.add("%" + filterText + "%");
}

if(browserQuery.showMenuItemsOnly) {
Expand All @@ -296,6 +323,26 @@ private Tuple2<String, List<Object>> selectQuery(final BrowserQuery browserQuery
return Tuple.of(sqlQuery.toString(), parameters);
}

/**
* Returns the appropriate column for the {@code Asset Name} field depending on the database that dotCMS is running
* on. That is, if the value is inside the "Content as JSON" column, or the legacy "text" column.
*
* @param baseQuery The base SQL query whose column name will be replaced.
*
* @return The appropriate database column for the Asset Name field.
*/
public static String getAssetNameColumn(final String baseQuery) {
String sql = baseQuery;
if (APILocator.getContentletJsonAPI().isJsonSupportedDatabase()) {
if (DbConnectionFactory.isPostgres()) {
sql = String.format(sql, POSTGRES_ASSETNAME_COLUMN);
} else {
sql = String.format(sql, MSSQL_ASSETNAME_COLUMN);
}
}
return sql;
}

private List<Map<String, Object>> includeLinks(final BrowserQuery browserQuery)
throws DotDataException, DotSecurityException {

Expand Down

0 comments on commit 164d3e8

Please sign in to comment.