Skip to content

Commit 9c21b98

Browse files
Merge pull request #1607 from research-software-directory/1604-unpublished-meta-pages
Don't expose unpublished meta pages in API
2 parents 09eca73 + b83592a commit 9c21b98

File tree

11 files changed

+103
-45
lines changed

11 files changed

+103
-45
lines changed

backend-tests/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!--
2-
SPDX-FileCopyrightText: 2023 - 2024 Ewan Cahen (Netherlands eScience Center) <[email protected]>
3-
SPDX-FileCopyrightText: 2023 - 2024 Netherlands eScience Center
2+
SPDX-FileCopyrightText: 2023 - 2025 Ewan Cahen (Netherlands eScience Center) <[email protected]>
3+
SPDX-FileCopyrightText: 2023 - 2025 Netherlands eScience Center
44
55
SPDX-License-Identifier: CC-BY-4.0
66
-->
@@ -26,7 +26,7 @@ Tests should be written taking the following principles in account:
2626

2727
## Contributing
2828

29-
This module uses [EditorConfig](https://editorconfig.org/) for basic formatting. Please check if your editor [already supports EditorConfig](https://editorconfig.org/#pre-installed) or if you need to [install a plugin](https://editorconfig.org/#download). A GitHub workflow is run on every PR to check if any files violate the formatting settings.
29+
This module uses [Prettier](https://prettier.io/) for code formatting. Please make sure your contributions comply with Prettier. A GitHub workflow is run on every PR to check if any files violate the formatting settings.
3030

3131
## Writing tests
3232

backend-tests/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ SPDX-License-Identifier: Apache-2.0
7070
<dependency>
7171
<groupId>io.rest-assured</groupId>
7272
<artifactId>rest-assured</artifactId>
73-
<version>5.5.5</version>
73+
<version>5.5.6</version>
7474
<scope>test</scope>
7575
</dependency>
7676

backend-tests/src/test/java/nl/esciencecenter/AuthenticationIntegrationTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ void givenUserWhoAgreedOnTerms_whenEditingSoftwareNotMaintainer_thenNowAllowed()
121121
.statusCode(204);
122122

123123
String getStartedUrl = "https://www.example.com";
124-
List response = RestAssured.given()
124+
List<?> response = RestAssured.given()
125125
.header(user.authHeader)
126126
.header(new Header("Prefer", "return=representation"))
127127
.contentType(ContentType.JSON)
@@ -159,7 +159,7 @@ void givenUnauthenticatedUser_whenViewingUnpublishedSoftware_thenNothingReturned
159159
.then()
160160
.statusCode(201);
161161

162-
List response = RestAssured.when()
162+
List<?> response = RestAssured.when()
163163
.get("software?slug=eq." + slug)
164164
.then()
165165
.statusCode(200)
@@ -247,7 +247,7 @@ void checkRPC_categoryPathsBySoftwareExpanded() {
247247

248248
// check if category IDs appear in proper location of result (=CategoryPath[])
249249
JsonArray jsonArray = JsonParser.parseString(response).getAsJsonArray();
250-
Assertions.assertEquals(jsonArray.size(), 2);
250+
Assertions.assertEquals(2, jsonArray.size());
251251
for (JsonElement jsonElement : jsonArray) {
252252
JsonArray categoryPath = jsonElement.getAsJsonArray();
253253
String shortName = categoryPath.get(1).getAsJsonObject().getAsJsonPrimitive("short_name").getAsString();
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// SPDX-FileCopyrightText: 2025 Ewan Cahen (Netherlands eScience Center) <[email protected]>
2+
// SPDX-FileCopyrightText: 2025 Netherlands eScience Center
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package nl.esciencecenter;
7+
8+
import io.restassured.RestAssured;
9+
import io.restassured.http.ContentType;
10+
import java.util.List;
11+
import org.junit.jupiter.api.Assertions;
12+
import org.junit.jupiter.api.Test;
13+
import org.junit.jupiter.api.extension.ExtendWith;
14+
15+
@ExtendWith({ SetupAllTests.class })
16+
public class MetaPagesIntegrationTest {
17+
18+
@Test
19+
void givenUnpublishedMetaPage_whenQueryingAnonymously_thenNothingFound() {
20+
String unpublishedMetaPageSlug = Commons.createUUID();
21+
RestAssured.given()
22+
.header(SetupAllTests.adminAuthHeader)
23+
.contentType(ContentType.JSON)
24+
.body(
25+
"{\"slug\": \"%s\", \"is_published\": false, \"title\": \"test meta page %s\"}".formatted(
26+
unpublishedMetaPageSlug,
27+
unpublishedMetaPageSlug
28+
)
29+
)
30+
.when()
31+
.post("meta_page")
32+
.then()
33+
.statusCode(201);
34+
35+
List<?> anonymousResponse = RestAssured.get("meta_page?slug=eq." + unpublishedMetaPageSlug)
36+
.then()
37+
.statusCode(200)
38+
.extract()
39+
.body()
40+
.as(List.class);
41+
Assertions.assertTrue(anonymousResponse.isEmpty());
42+
43+
List<?> adminResponse = RestAssured.given()
44+
.header(SetupAllTests.adminAuthHeader)
45+
.get("meta_page?slug=eq." + unpublishedMetaPageSlug)
46+
.then()
47+
.statusCode(200)
48+
.extract()
49+
.body()
50+
.as(List.class);
51+
Assertions.assertEquals(1, adminResponse.size());
52+
}
53+
}

backend-tests/src/test/java/nl/esciencecenter/UserDeletingItemsIntegrationTest.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// SPDX-FileCopyrightText: 2024 Ewan Cahen (Netherlands eScience Center) <[email protected]>
2-
// SPDX-FileCopyrightText: 2024 Netherlands eScience Center
1+
// SPDX-FileCopyrightText: 2024 - 2025 Ewan Cahen (Netherlands eScience Center) <[email protected]>
2+
// SPDX-FileCopyrightText: 2024 - 2025 Netherlands eScience Center
33
//
44
// SPDX-License-Identifier: Apache-2.0
55

@@ -22,7 +22,7 @@ void givenAnonymousUser_whenCallingSoftwareDeleteEndpoint_thenErrorReturned() {
2222
.header(Commons.requestEntry)
2323
.contentType(ContentType.JSON)
2424
.body(
25-
"{\"slug\": \"%s\", \"is_published\": true, \"brand_name\": \"test software\"}".formatted(softwareSlug)
25+
"{\"slug\": \"%s\", \"is_published\": true, \"brand_name\": \"test software\"}".formatted(softwareSlug)
2626
)
2727
.when()
2828
.post("software")
@@ -56,7 +56,7 @@ void givenRegularUser_whenCallingSoftwareDeleteEndpoint_thenErrorReturned() {
5656
.header(Commons.requestEntry)
5757
.contentType(ContentType.JSON)
5858
.body(
59-
"{\"slug\": \"%s\", \"is_published\": true, \"brand_name\": \"test software\"}".formatted(softwareSlug)
59+
"{\"slug\": \"%s\", \"is_published\": true, \"brand_name\": \"test software\"}".formatted(softwareSlug)
6060
)
6161
.when()
6262
.post("software")
@@ -90,7 +90,7 @@ void givenRegularUser_whenCallingProjectDeleteEndpoint_thenErrorReturned() {
9090
.header(user.authHeader)
9191
.header(Commons.requestEntry)
9292
.contentType(ContentType.JSON)
93-
.body("{\"slug\": \"%s\", \"is_published\": true, \"title\": \"test project\"}".formatted(projectSlug))
93+
.body("{\"slug\": \"%s\", \"is_published\": true, \"title\": \"test project\"}".formatted(projectSlug))
9494
.when()
9595
.post("project")
9696
.then()
@@ -123,7 +123,7 @@ void givenRegularUser_whenCallingOrganisationDeleteEndpoint_thenErrorReturned()
123123
.header(user.authHeader)
124124
.header(Commons.requestEntry)
125125
.contentType(ContentType.JSON)
126-
.body("{\"slug\": \"%s\", \"name\": \"test organisation\"}".formatted(organisationSlug))
126+
.body("{\"slug\": \"%s\", \"name\": \"test organisation\"}".formatted(organisationSlug))
127127
.when()
128128
.post("organisation")
129129
.then()
@@ -154,7 +154,7 @@ void givenRegularUser_whenCallingCommunityDeleteEndpoint_thenErrorReturned() {
154154
.header(SetupAllTests.adminAuthHeader)
155155
.header(Commons.requestEntry)
156156
.contentType(ContentType.JSON)
157-
.body("{\"slug\": \"%s\", \"name\": \"test community\"}".formatted(communitySlug))
157+
.body("{\"slug\": \"%s\", \"name\": \"test community\"}".formatted(communitySlug))
158158
.when()
159159
.post("community")
160160
.then()

data-generation/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1260,7 +1260,7 @@ const globalCategoryPromise = Promise.all([softwarePromise, categoryPromise])
12601260
.then(() => 'global categories for software done');
12611261
globalPromises.push(globalCategoryPromise);
12621262

1263-
const metaPagesPromise = postToBackend('/meta_pages', generateMetaPages()).then(() => console.log('meta pages done'));
1263+
const metaPagesPromise = postToBackend('/meta_page', generateMetaPages()).then(() => console.log('meta pages done'));
12641264
globalPromises.push(metaPagesPromise);
12651265

12661266
const newsPromise = imageIdsPromise.then(imageIds =>

database/017-meta-pages.sql

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
-- SPDX-FileCopyrightText: 2021 - 2024 Ewan Cahen (Netherlands eScience Center) <[email protected]>
2-
-- SPDX-FileCopyrightText: 2021 - 2024 Netherlands eScience Center
1+
-- SPDX-FileCopyrightText: 2021 - 2025 Ewan Cahen (Netherlands eScience Center) <[email protected]>
2+
-- SPDX-FileCopyrightText: 2021 - 2025 Netherlands eScience Center
33
-- SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
44
-- SPDX-FileCopyrightText: 2022 dv4all
55
--
@@ -8,7 +8,7 @@
88
-- CUSTOM META PAGES TO BE ADDED TO RSD
99
-- THE PAGES ARE LISTED IN THE FOOTER
1010

11-
CREATE TABLE meta_pages (
11+
CREATE TABLE meta_page (
1212
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
1313
slug VARCHAR(100) UNIQUE NOT NULL CHECK (slug ~ '^[a-z0-9]+(-[a-z0-9]+)*$'),
1414
title VARCHAR(100) NOT NULL,
@@ -20,7 +20,7 @@ CREATE TABLE meta_pages (
2020
);
2121

2222

23-
CREATE FUNCTION sanitise_insert_meta_pages() RETURNS TRIGGER LANGUAGE plpgsql AS
23+
CREATE FUNCTION sanitise_insert_meta_page() RETURNS TRIGGER LANGUAGE plpgsql AS
2424
$$
2525
BEGIN
2626
NEW.id = gen_random_uuid();
@@ -30,11 +30,11 @@ BEGIN
3030
END
3131
$$;
3232

33-
CREATE TRIGGER sanitise_insert_meta_pages BEFORE INSERT ON meta_pages
34-
FOR EACH ROW EXECUTE PROCEDURE sanitise_insert_meta_pages();
33+
CREATE TRIGGER sanitise_insert_meta_page BEFORE INSERT ON meta_page
34+
FOR EACH ROW EXECUTE PROCEDURE sanitise_insert_meta_page();
3535

3636

37-
CREATE FUNCTION sanitise_update_meta_pages() RETURNS TRIGGER LANGUAGE plpgsql AS
37+
CREATE FUNCTION sanitise_update_meta_page() RETURNS TRIGGER LANGUAGE plpgsql AS
3838
$$
3939
BEGIN
4040
NEW.id = OLD.id;
@@ -52,5 +52,16 @@ BEGIN
5252
END
5353
$$;
5454

55-
CREATE TRIGGER sanitise_update_meta_pages BEFORE UPDATE ON meta_pages
56-
FOR EACH ROW EXECUTE PROCEDURE sanitise_update_meta_pages();
55+
CREATE TRIGGER sanitise_update_meta_page BEFORE UPDATE ON meta_page
56+
FOR EACH ROW EXECUTE PROCEDURE sanitise_update_meta_page();
57+
58+
59+
-- row level security
60+
ALTER TABLE meta_page ENABLE ROW LEVEL SECURITY;
61+
62+
CREATE POLICY anyone_can_read ON meta_page FOR SELECT TO rsd_web_anon, rsd_user
63+
USING (is_published);
64+
65+
CREATE POLICY admin_all_rights ON meta_page TO rsd_admin
66+
USING (TRUE)
67+
WITH CHECK (TRUE);

database/020-row-level-security.sql

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -792,16 +792,6 @@ CREATE POLICY admin_all_rights ON project_for_organisation TO rsd_admin
792792
WITH CHECK (TRUE);
793793

794794

795-
-- meta-pages
796-
ALTER TABLE meta_pages ENABLE ROW LEVEL SECURITY;
797-
798-
CREATE POLICY anyone_can_read ON meta_pages FOR SELECT TO rsd_web_anon, rsd_user
799-
USING (TRUE);
800-
801-
CREATE POLICY admin_all_rights ON meta_pages TO rsd_admin
802-
USING (TRUE)
803-
WITH CHECK (TRUE);
804-
805795

806796
-- backend logs
807797
ALTER TABLE backend_log ENABLE ROW LEVEL SECURITY;

frontend/components/admin/pages/saveMarkdownPage.test.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all)
44
// SPDX-FileCopyrightText: 2024 - 2025 Dusan Mijatovic (Netherlands eScience Center)
55
// SPDX-FileCopyrightText: 2024 - 2025 Netherlands eScience Center
6+
// SPDX-FileCopyrightText: 2025 Ewan Cahen (Netherlands eScience Center) <[email protected]>
67
//
78
// SPDX-License-Identifier: Apache-2.0
89

@@ -27,7 +28,7 @@ beforeEach(() => {
2728
})
2829

2930
it('addMarkdownPage', async() => {
30-
const expectUrl = '/api/v1/meta_pages'
31+
const expectUrl = '/api/v1/meta_page'
3132
const expectBody = {
3233
'body': '{"id":null,"slug":"test-slug","title":"Test title 1","description":null,"is_published":false,"position":1}',
3334
'headers': {
@@ -66,7 +67,7 @@ it('addMarkdownPage', async() => {
6667
it('saveMarkdownPage', async () => {
6768
mockParams.page.id = 'test-page-id'
6869

69-
const expectUrl = `/api/v1/meta_pages?id=eq.${mockParams.page.id}`
70+
const expectUrl = `/api/v1/meta_page?id=eq.${mockParams.page.id}`
7071
const expectBody = {
7172
'body': '{"id":"test-page-id","slug":"test-slug","title":"Test title 1","description":null,"is_published":false,"position":1}',
7273
'headers': {
@@ -121,7 +122,7 @@ it('deleteMarkdownPage', async() => {
121122
token: 'TEST-TOKEN'
122123
}
123124

124-
const expectedUrl = `/api/v1/meta_pages?slug=eq.${params.slug}`
125+
const expectedUrl = `/api/v1/meta_page?slug=eq.${params.slug}`
125126
const expectBody = {
126127
'headers': {
127128
'Authorization': `Bearer ${params.token}`,

frontend/components/admin/pages/saveMarkdownPage.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// SPDX-FileCopyrightText: 2022 - 2023 Dusan Mijatovic (dv4all)
22
// SPDX-FileCopyrightText: 2022 - 2023 dv4all
33
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all) (dv4all)
4+
// SPDX-FileCopyrightText: 2025 Ewan Cahen (Netherlands eScience Center) <[email protected]>
5+
// SPDX-FileCopyrightText: 2025 Netherlands eScience Center
46
//
57
// SPDX-License-Identifier: Apache-2.0
68

@@ -11,7 +13,7 @@ import {MarkdownPage} from './useMarkdownPages'
1113

1214
export async function addMarkdownPage({page,token}:{page:MarkdownPage,token:string}) {
1315
try {
14-
const query = 'meta_pages'
16+
const query = 'meta_page'
1517
const url = `/api/v1/${query}`
1618

1719
const resp = await fetch(url,{
@@ -43,7 +45,7 @@ export async function addMarkdownPage({page,token}:{page:MarkdownPage,token:stri
4345

4446
export async function saveMarkdownPage({page,token}:{page:MarkdownPage,token:string}) {
4547
try {
46-
const query = `meta_pages?id=eq.${page.id}`
48+
const query = `meta_page?id=eq.${page.id}`
4749
const url = `/api/v1/${query}`
4850

4951
const resp = await fetch(url,{
@@ -111,7 +113,7 @@ export async function updatePagePositions({items,token}:{items:RsdLink[],token:s
111113

112114
export async function patchMarkdownData({id,data,token}:{id:string,data:any,token:string}) {
113115
try {
114-
const query = `meta_pages?id=eq.${id}`
116+
const query = `meta_page?id=eq.${id}`
115117
const url = `/api/v1/${query}`
116118

117119
const resp = await fetch(url,{
@@ -134,7 +136,7 @@ export async function patchMarkdownData({id,data,token}:{id:string,data:any,toke
134136

135137
export async function deleteMarkdownPage({slug,token}:{slug:string,token:string}) {
136138
try {
137-
const query = `meta_pages?slug=eq.${slug}`
139+
const query = `meta_page?slug=eq.${slug}`
138140
const url = `/api/v1/${query}`
139141

140142
const resp = await fetch(url,{

0 commit comments

Comments
 (0)