Skip to content

Commit

Permalink
Merge branch 'main' of github.com:dricazenck/wcc-backend into update_…
Browse files Browse the repository at this point in the history
…footer_landingPage_data
  • Loading branch information
dricazenck committed Dec 7, 2024
2 parents 48beb85 + 6f71db1 commit 4c5f20e
Show file tree
Hide file tree
Showing 15 changed files with 196 additions and 124 deletions.
69 changes: 22 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@
* [Perform SONAR ANALYSIS](#perform-sonar-analysis)
* [Deploy application](#deploy-application)
* [Deploy with docker compose](#deploy-with-docker-compose)
* [Deploy with docker](#deploy-with-docker)
* [Start docker with remote debug](#start-docker-with-remote-debug)
* [Start docker with mounted data volume](#start-docker-with-mounted-data-volume)
* [Helpful commands with docker](#helpful-commands-with-docker)
* [Deploy with Fly.io](#deploy-with-flyio)
* [Setup Fly.io locally](#setup-flyio-locally)
Expand Down Expand Up @@ -156,24 +153,24 @@ Once you've done that, restart the IDE.
**Note**: Make sure you have docker daemon running locally to be able to run integration test, by
execute ``docker ps``

* Create Jar

```shell
./gradlew clean bootJar
```

* Start database

```shell
docker run --pull always --name surrealdb -p 8000:8000 -d surrealdb/surrealdb:latest start
docker run --pull always --name surrealdb -p 8000:8000 -d surrealdb/surrealdb:latest start --user root --pass root --log debug
```

* Start Spring Boot Application:
* Start Spring Boot Application (from your IDE):

```shell
./gradlew bootRun
```

**Note**: You can start application in a debug mode through your IDE.

IntelliJ IDEA:
Select \src\main\java\com\wcc\platform\PlatformApplication.java and mouse right-click to
select debugging option.

* Access application on http://localhost:8080/api/cms/v1/team

## Open API Documentation
Expand Down Expand Up @@ -273,55 +270,33 @@ Generate token to replace in the project.

### Deploy with docker compose

* build create jar: `./gradlew clean bootJar`
* Start docker compose

```shell
docker compose -f docker/docker-compose.yml up --build
```

* Stop docker compose
* Build and create jar

```shell
cd docker
docker compose down
```
./gradlew clean bootJar`
```

### Deploy with docker

* build create jar: `./gradlew clean bootJar`

* start app via docker
* Start docker compose

```shell
docker build -t wcc-backend .
docker run -d -p 8080:8080 --name wcc-backend-container wcc-backend
docker compose -f docker/docker-compose.yml up --build
```

#### Start docker with remote debug
**Note**: This will create two Docker instances in your Docker desktop:

```shell
docker build -t wcc-backend .
docker run -p 8080:8080 -p 5005:5005 --name wcc-backend-container wcc-backend
```
1. surrealdb
2. springboot-app

#### Start docker with mounted data volume
* Debug application

If you are running your Spring Boot application inside a Docker container, ensure that the external
directory path is accessible from within the container.
To debug application STOP the docker container of the application, springboot-app. Do not stop the
container of the SurrealDB. Start the application from your IDE.

* Windows:

```shell
docker run -v ${PWD}/data:/app/data -d -p 8080:8080 --name wcc-backend-container wcc-backend

```

* Linux:
* Stop docker compose

```shell
docker run -v $(pwd)/data:/app/data -d -p 8080:8080 --name wcc-backend-container wcc-backend

cd docker
docker compose down
```

#### Helpful commands with docker
Expand Down
12 changes: 12 additions & 0 deletions integration-test/tests/cms/codeofconduct.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {expect, test} from '@playwright/test';
import { codeofconductExepctedInformation } from '../../utils/datafactory/codeofconduct.data';
test('GET /api/cms/v1/code-of-conduct returns correct data', async ({request}) => {
const response = await request.get(`/api/cms/v1/code-of-conduct`);

expect(response.status()).toBe(200);
const body = await response.json();

const expectedResponse = codeofconductExepctedInformation;

expect(body).toEqual(expectedResponse);
});
6 changes: 6 additions & 0 deletions integration-test/tests/cms/events.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import {expect, test} from '@playwright/test';

test('GET /api/cms/v1/events returns success response code', async ({request}) => {
const response = await request.get(`/api/cms/v1/events`);
expect(response.status()).toBe(200);
});
12 changes: 12 additions & 0 deletions integration-test/tests/cms/mentorshipoverview.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {expect, test} from '@playwright/test';
test('GET /api/cms/v1/mentorship/overview returns correct data', async ({request}) => {
const response = await request.get('/api/cms/v1/mentorship/overview');
expect(response.status()).toBe(200);
const data = await response.json();
expect(data.page).toBeDefined();
expect(data.page.title).toBe('Mentorship Programme');
expect(data.mentorSection).toBeDefined();
expect(data.mentorSection.title).toBe('Become a Mentor');
expect(data.menteeSection).toBeDefined();
expect(data.menteeSection.title).toBe('Become a Mentee');
});
38 changes: 38 additions & 0 deletions integration-test/utils/datafactory/codeofconduct.data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export const codeofconductExepctedInformation = {
"page": {
"title": "Code of Conduct",
"description": "At Women Coding Community we are committed to a vibrant, supportive community where women can network, share experiences, and foster professional relationships, regardless of age, gender, visible or invisible disability, ethnicity, gender expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, sexual orientation or preferred programming language(s)."
},
"items": [
{
"title": "Our Standards",
"description": "To ensure a positive experience for all members, we expect participants to exhibit the following behaviors:",
"items": [
"Respect: Treat everyone with respect, dignity, and empathy. Listen and communicate thoughtfully.",
"Inclusivity: Actively seek to acknowledge and respect the diversity of our community.",
"Collaboration: Share knowledge generously and assist others when possible, fostering a collaborative atmosphere.",
"Constructive Communication: Engage in constructive, positive communication. Provide and gracefully accept constructive criticism.",
"Professionalism: Be professional in all interactions within the community. Avoid behavior or language that may be considered inappropriate or offensive."
]
},
{
"title": "Unacceptable Behavior",
"description": "The following behaviors are considered harassment and are unacceptable within our community:",
"items": [
"Violence, threats of violence, or violent language directed against another member or group.",
"Sexist, racist, homophobic, transphobic, ableist, or otherwise discriminatory jokes and language.",
"Personal insults, particularly those related to gender, sexual orientation, race, religion, or disability.",
"Inappropriate photography or recording.",
"Advocating for, or encouraging, any of the above behavior."
]
},
{
"title": "Enforcement",
"description": "Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Instances of abusive, harassing, or otherwise unacceptable behavior can be reported by <a href=\"mailto:[email protected]\">email</a>. All complaints will be reviewed and investigated promptly and fairly."
},
{
"title": "Consequences",
"description": "Actions determined to be contrary to these guidelines may result in consequences ranging from a warning to expulsion from the community, future events depending on the severity of the behavior."
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.NOT_FOUND;

import com.surrealdb.connection.exception.SurrealException;
import com.wcc.platform.domain.exceptions.ContentNotFoundException;
import com.wcc.platform.domain.exceptions.DuplicatedMemberException;
import com.wcc.platform.domain.exceptions.ErrorDetails;
Expand Down Expand Up @@ -38,7 +39,11 @@ public ResponseEntity<ErrorDetails> handleNotFoundException(
}

/** Receive PlatformInternalException and return {@link HttpStatus#INTERNAL_SERVER_ERROR}. */
@ExceptionHandler({PlatformInternalException.class, FileRepositoryException.class})
@ExceptionHandler({
PlatformInternalException.class,
FileRepositoryException.class,
SurrealException.class
})
@ResponseStatus(INTERNAL_SERVER_ERROR)
public ResponseEntity<ErrorDetails> handleInternalError(
final RuntimeException ex, final WebRequest request) {
Expand Down
13 changes: 3 additions & 10 deletions src/main/java/com/wcc/platform/configuration/RepositoryConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import com.surrealdb.driver.SyncSurrealDriver;
import com.wcc.platform.domain.cms.pages.FooterPage;
import com.wcc.platform.domain.cms.pages.LandingPage;
import com.wcc.platform.repository.MemberRepository;
import com.wcc.platform.repository.PageRepository;
import com.wcc.platform.repository.ResourceContentRepository;
Expand All @@ -24,14 +22,9 @@ public ResourceContentRepository getResourceRepository(final SyncSurrealDriver d
return new SurrealDbResourceRepository(driver);
}

@Bean(name = "footerRepository")
public PageRepository<FooterPage> getFooterPageRepository(final SyncSurrealDriver driver) {
return new SurrealDbPageRepository<>(driver, FooterPage.class);
}

@Bean(name = "landingPageRepository")
public PageRepository<LandingPage> getLandingPageRepository(final SyncSurrealDriver driver) {
return new SurrealDbPageRepository<>(driver, LandingPage.class);
@Bean
public PageRepository getPageRepository(final SyncSurrealDriver driver) {
return new SurrealDbPageRepository(driver);
}

/** Create FileMemberRepository bean. */
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package com.wcc.platform.domain.exceptions;

import com.wcc.platform.domain.cms.PageType;

/** Platform generic exception. */
public class PlatformInternalException extends RuntimeException {

public PlatformInternalException(final String message, final Throwable cause) {
super(message, cause);
}

public PlatformInternalException(final PageType pageType, final Throwable cause) {
super("Invalid Page type " + pageType, cause);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.wcc.platform.repository;

/** Generic page repository interface. */
public interface PageRepository<T> extends CrudRepository<T, String> {}
public interface PageRepository extends CrudRepository<String, String> {}
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,23 @@
import java.util.Optional;

/** SurrealDB repository implementation for page. */
public class SurrealDbPageRepository<T> implements PageRepository<T> {
public class SurrealDbPageRepository implements PageRepository {

/* default */ static final String TABLE = "page";

private final SyncSurrealDriver driver;
private final Class<T> entityType;

public SurrealDbPageRepository(final SyncSurrealDriver driver, final Class<T> entityType) {
public SurrealDbPageRepository(final SyncSurrealDriver driver) {
this.driver = driver;
this.entityType = entityType;
}

@Override
public T create(final T entity) {
public String create(final String entity) {
return driver.create(TABLE, entity);
}

@Override
public T update(final String id, final T entity) {
public String update(final String id, final String entity) {
final var result = driver.update(id, entity);

if (result.isEmpty()) {
Expand All @@ -36,15 +34,15 @@ public T update(final String id, final T entity) {
}

@Override
public Collection<T> findAll() {
return driver.select(TABLE, entityType);
public Collection<String> findAll() {
return driver.select(TABLE, String.class);
}

@Override
public Optional<T> findById(final String id) {
public Optional<String> findById(final String id) {
final var key = TABLE + ":" + id;
final var query =
driver.query("SELECT * FROM " + TABLE + " WHERE id = $id", Map.of("id", key), entityType);
driver.query("SELECT * FROM " + TABLE + " WHERE id = $id", Map.of("id", key), String.class);

if (query.isEmpty()) {
return Optional.empty();
Expand Down
36 changes: 23 additions & 13 deletions src/main/java/com/wcc/platform/service/CmsService.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,19 @@
import com.wcc.platform.repository.PageRepository;
import com.wcc.platform.utils.FileUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

/** CMS service responsible for simple pages. */
@Service
public class CmsService {
private final ObjectMapper objectMapper;
private final PageRepository<FooterPage> footerRepository;
private final PageRepository<LandingPage> lpRepository;
private final PageRepository pageRepository;

/** Init repositories with respective qualifiers. */
@Autowired
public CmsService(
final ObjectMapper objectMapper,
@Qualifier("footerRepository") final PageRepository<FooterPage> footerRepository,
@Qualifier("landingPageRepository") final PageRepository<LandingPage> lpRepository) {
public CmsService(final ObjectMapper objectMapper, final PageRepository pageRepository) {
this.objectMapper = objectMapper;
this.footerRepository = footerRepository;
this.lpRepository = lpRepository;
this.pageRepository = pageRepository;
}

/**
Expand All @@ -54,8 +48,17 @@ public TeamPage getTeam() {
* @return Footer page
*/
public FooterPage getFooter() {
final var page = footerRepository.findById(PageType.FOOTER.name());
return page.orElseGet(this::getFooterFallback);
final var page = pageRepository.findById(PageType.FOOTER.name());

if (page.isPresent()) {
try {
return objectMapper.readValue(page.get(), FooterPage.class);
} catch (JsonProcessingException e) {
throw new PlatformInternalException(e.getMessage(), e);
}
}

return getFooterFallback();
}

private FooterPage getFooterFallback() {
Expand All @@ -73,9 +76,16 @@ private FooterPage getFooterFallback() {
* @return Landing page of the community.
*/
public LandingPage getLandingPage() {
final var page = lpRepository.findById(PageType.LANDING_PAGE.name());
final var page = pageRepository.findById(PageType.LANDING_PAGE.name());
if (page.isPresent()) {
try {
return objectMapper.readValue(page.get(), LandingPage.class);
} catch (JsonProcessingException e) {
throw new PlatformInternalException(e.getMessage(), e);
}
}

return page.orElseGet(this::getLandingPageFallback);
return getLandingPageFallback();
}

private LandingPage getLandingPageFallback() {
Expand Down
Loading

0 comments on commit 4c5f20e

Please sign in to comment.